﻿//++
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
// Module Name:
//
//  InstantMessageReminder.cs
//    
// Abstract:
//
//  Workflow application for controlling the callflow of a
//  reminder for an instant messaging session.
//  
//--

using System;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Workflow.Activities;
using Microsoft.EnhancedReminders.Dispatcher.Workflow;
using Microsoft.OfficeCommunicationsServer.Applications.Common;
using Microsoft.Rtc.Workflow.Activities;
using Microsoft.Speech.Recognition;

namespace Microsoft.EnhancedReminders.Dispatcher.Workflow
{
    /// <summary>
    /// Workflow class for controlling the call flow of voicemail reminders
    /// </summary>
    public sealed partial class InstantMessageReminder : SequentialWorkflowActivity
    {
        private NotificationItem _message;
        private NotificationResult _result;

        /// <summary>
        /// Get or set the NotificationItem to be delivered. This is intended
        /// to be used as an input parameter.
        /// </summary>
        public NotificationItem Message
        {
            get
            {
                return _message;
            }
            set
            {
                _message = value;
                _result = new NotificationResult(_message, NotificationResultStatus.Error,
                    NotificationChannelType.None);
            }
        }

        /// <summary>
        /// Get or set the NotificationResult from the attempt to deliver
        /// the notification item. This is intended to be accessed as a
        /// return value.
        /// </summary>
        public NotificationResult MessageResult
        {
            get
            {
                return _result;
            }
            set
            {
                _result = value;
            }
        }

        /// <summary>
        /// ctor.
        /// </summary>
        public InstantMessageReminder()
        {
            InitializeComponent();
        }

        /// <summary>
        /// Called when the primary QA starts. Sets the prompts and grammars.
        /// </summary>
        private void askReminderTurnStarting(object sender, InstantMessagingTurnStartingEventArgs e)
        {
            Logger.WriteTraceInformation(Message.Context, "Workflow: Sending instant message notification message");

            if (askReminder.Grammars.Count == 0)
            {
                askReminder.MainPrompt = GetNotificationMessage();
                askReminder.Prompts.SilencePrompt = string.Format(CultureInfo.CurrentUICulture, PromptResources.InstantMessage_Silence, GetNotificationOptions());
                askReminder.Prompts.EscalatedSilencePrompt = PromptResources.InstantMessage_EscalatedSilence;
                askReminder.Prompts.NoRecognitionPrompt = string.Format(CultureInfo.CurrentUICulture, PromptResources.InstantMessage_NoRecognition, GetNotificationOptions());
                askReminder.Prompts.EscalatedNoRecognitionPrompt = string.Format(CultureInfo.CurrentUICulture, PromptResources.InstantMessage_EscalatedNoRecognition, GetExpandedNotificationOptions());
                askReminder.Prompts.HelpPrompt = GetExpandedNotificationOptions();

                string basePath = Path.GetDirectoryName(this.GetType().Assembly.Location) + "\\";
                CalendarNotificationItem calendarNotification = Message as CalendarNotificationItem;

                if (calendarNotification != null && calendarNotification.IsJoinNow)
                {
                    askReminder.Grammars.Add(new Grammar(basePath + Helpers.GetSetting<string>("VoiceGrammar",null), "InstantMessageJoinNow"));
                }
                else
                {
                    askReminder.Grammars.Add(new Grammar(basePath + Helpers.GetSetting<string>("VoiceGrammar",null), "InstantMessage"));
                }
                reminderHelpCommand.Grammar = new Grammar(basePath + Helpers.GetSetting<string>("VoiceGrammar", null), "InstantMessageHelp");

                if (calendarNotification != null && calendarNotification.IsJoinNow)
                {
                    joinNowActivity1.Notification = calendarNotification;
                }
            }
        }

        /// <summary>
        /// Called when the "Goodbye" statement starts. Logs the turn and sets the prompt.
        /// </summary>
        private void GoodbyeTurnStarting(object sender, InstantMessagingTurnStartingEventArgs e)
        {
            Logger.WriteTraceInformation(Message.Context, "Workflow: Sending goodbye message.");
            goodbye.MainPrompt = PromptResources.InstantMessage_Dismiss;
        }

        /// <summary>
        /// Called when the "Goodbye from no recos" statement starts. Logs the turn and sets the prompt.
        /// </summary>
        private void GoodbyeNoRecoTurnStarting(object sender, InstantMessagingTurnStartingEventArgs  e)
        {
            Logger.WriteTraceInformation(Message.Context, "Instant Message Workflow hit maximum no recognition events.");
            goodbyeNoReco.MainPrompt = PromptResources.InstantMessage_GoodbyeNoReco;
        }

        /// <summary>
        /// Called when the "Goodbye from silences" statement starts. Logs the turn and sets the prompt.
        /// </summary>
        private void goodbyeSilenceTurnStarting(object sender, InstantMessagingTurnStartingEventArgs  e)
        {
            Logger.WriteTraceInformation(Message.Context, "Instant Message Workflow hit maximum silence events.");
            goodbyeSilence.MainPrompt = PromptResources.InstantMessage_EscalatedSilence;
        }

        /// <summary>
        /// Get the initial notification message.
        /// </summary>
        /// <returns>The text of the notification that will be delivered</returns>
        private string GetNotificationMessage()
        {
            Debug.Assert(_message != null, "_message != null");

            string introMessage = null;

            MeetingNotificationItem meetingNotification = _message as MeetingNotificationItem;
            CalendarNotificationItem calendarNotification = _message as CalendarNotificationItem;

            if (meetingNotification != null)
            {
                Debug.Assert(!String.IsNullOrEmpty(meetingNotification.NotificationOriginator), "!String.IsNullOrEmpty(meetingNotification.NotificationOriginator)");
                Debug.Assert(!String.IsNullOrEmpty(meetingNotification.Message), "!String.IsNullOrEmpty(meetingNotification.Message)");

                introMessage = string.Format(CultureInfo.CurrentUICulture,
                    IMResources.Meeting_Intro,
                    meetingNotification.NotificationOriginator,
                    DispatcherHelpers.GetLeadTime(CultureInfo.CurrentUICulture, TimeZoneInfo.Local, meetingNotification.StartTime, new InstantMessageTimeSpanFormatter()),
                    meetingNotification.Message,
                    meetingNotification.Location,
                    GetNotificationOptions());
            }
            else if (calendarNotification != null)
            {
                introMessage = string.Format(CultureInfo.CurrentUICulture,
                    IMResources.Appointment_Intro,
                    DispatcherHelpers.GetLeadTime(CultureInfo.CurrentUICulture, TimeZoneInfo.Local, calendarNotification.StartTime, new InstantMessageTimeSpanFormatter()),
                    calendarNotification.Message,
                    calendarNotification.Location,
                    GetNotificationOptions());
            }
            else if (_message is VoicemailNotificationItem)
            {
                introMessage = IMResources.Voicemail_Intro;
            }
            else
            {
                Debug.Assert(false, "Unknown notification category was passed to GetNotificationMessage.");
            }

            return introMessage;
        }

        /// <summary>
        /// Gets a string containing the valid response options for a particular notification.
        /// </summary>
        private string GetNotificationOptions()
        {
            string options = IMResources.Response_Dismiss;

            CalendarNotificationItem calendarNotification = Message as CalendarNotificationItem;

            if (calendarNotification != null && calendarNotification.IsJoinNow)
            {
                options = string.Format(CultureInfo.CurrentUICulture, "{0}\n{1}",
                    string.Format(CultureInfo.CurrentUICulture, IMResources.Response_Split, IMResources.Response_JoinNow),
                    options);
            }

            return options;
        }

        /// <summary>
        /// Returns a string containing expanded help options for this notification.
        /// </summary>
        private string GetExpandedNotificationOptions()
        {
            string options = PromptResources.InstantMessage_Help_Dismiss;
            CalendarNotificationItem calendarNotification = Message as CalendarNotificationItem;

            if (calendarNotification != null && calendarNotification.IsJoinNow)
            {
                options = string.Format(CultureInfo.CurrentUICulture, "{0} {1}", PromptResources.InstantMessage_Help_JoinNow, options);
            }

            return options;            
        }

        /// <summary>
        /// Handles recognition of "Dismiss" response.
        /// </summary>
        private void IfDismissRecognized(object sender, ConditionalEventArgs e)
        {
            _result.Status = NotificationResultStatus.Success;

            if (askReminder.RecognitionResult.Semantics.Value as string == "Dismiss")
            {
                Logger.WriteTraceInformation(Message.Context, "Workflow: Recognized 'dismiss' response.");

                e.Result = true;
            }
            else
            {
                // since the only other response we recognize is join now, it is implied that we received
                // a "join now" response if we get here.
                Logger.WriteTraceInformation(Message.Context, "Workflow: Recognized 'join now' response.");
            }
        }

        /// <summary>
        /// This method is called when any exception occurs within the workflow.  It does some 
        /// generic exception logging for debugging purposes.
        /// </summary>
        private void HandleGeneralFault(object sender, EventArgs e)
        {
            // When an exception is thrown the actual exception is stored in the Fault property,
            // which is read-only.  Check this value for error information; if it is an exception, 
            // ToString() will include a full stack trace of all inner exceptions.
            Logger.WriteTraceError(Message.Context, generalFaultHandler.Fault, "Unhandled exception in workflow");

            if (Debugger.IsAttached)
            {
                // If the debugger is attached, break here so that you can see the error that occurred.
                Debugger.Break();
            }
        }
    }
}
